<?php


namespace App\Common;

use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Parser;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use Lcobucci\JWT\Signer\Key;
use Lcobucci\JWT\ValidationData;

/**
 * 单例 所有请求中使用JWT的唯一实例
 * Class JwtAuth
 * @package App\Common
 */
class JwtAuth
{
    private $token;
    private $iss = 'api.demo.com'; //签发方
    private $aud = 'demo_server_app'; //接收方
    private $uid; // 用户ID
    private $identified = 'fa3243949sl84ct'; //鉴权ID-唯一标识
    private $sign; // 密钥实例
    private $secret; // KEY实例
    private $key = '^&^%^(@*7667235^%^jijGRE3943&*&$'; // 密钥值
    //单例模式 jwtAuth实例
    private static $instance;
    // 用户上传的token
    private $decodeToken;

    /**
     * 私有化 构造方法
     * JwtAuth constructor.
     */
    private function __construct()
    {
        $this->sign = new Sha256();
        $this->secret = new Key($this->key);
    }

    /**
     * 获取jwtAuth 的实例
     * @return JwtAuth
     */
    public static function getInstance()
    {
        if (is_null(self::$instance)) {
            self::$instance = new self();
        }
        return self::$instance;
    }


    /**
     * 私有化 clone函数
     */
    private function __clone()
    {
        // TODO: Implement __clone() method.
    }

    /**
     * 解析并获取token 字符串
     * @return string
     */
    public function getToken()
    {
        return (string)$this->token;
    }


    /**
     * 设置 token
     * @param $token
     * @return $this
     */
    public function setToken($token)
    {
        $this->token = $token;
        return $this;
    }

    /**
     * 设置 UID
     * @param mixed $uid
     */
    public function setUid($uid)
    {
        $this->uid = $uid;
        return $this;
    }

    /**
     * 生成 jwt token对象
     * @return $this
     */
    public function encode()
    {
        $time = time();
        $this->token = (new Builder())
            ->withHeader('alg', 'HS256')
            ->issuedBy($this->iss)
            ->permittedFor($this->aud)
            ->identifiedBy($this->identified, true)
            ->issuedAt($time)
            ->expiresAt($time + 3600)
            ->withClaim('uid', $this->uid)
            ->getToken($this->sign, $this->secret);
        return $this;
    }

    /**
     * 将 token字符串解析成 token对象
     * @return \Lcobucci\JWT\Token
     */
    public function decode()
    {
        if (!$this->decodeToken) {
            $this->decodeToken = (new Parser())->parse((string)$this->token);
            $this->uid = $this->decodeToken->getClaim('uid');
        }
        return $this->decodeToken;
    }

    /**
     * validate验证信息
     * @return bool
     */
    public function validate()
    {
        $data = new ValidationData();
        $data->setIssuer($this->iss);
        $data->setAudience($this->aud);
        $data->setId($this->identified);
        return $this->decode()->validate($data);
    }

    /**
     * 验证token
     * @return bool
     */
    public function verify()
    {
        $result = $this->decode()->verify($this->sign, $this->secret);
        return $result;
    }

}
